package shapes.shapes2D.polygon 
{
	import flash.display.Graphics;
	import flash.geom.Point;
	import shapes.shapes2D.BaseShape;
	import shapes.shapes2D.Line;
	/**
	 * @author Nicolas Barradeau
	 * http://en.nicoptere.net
	 */
	public class Polygon extends BaseShape
	{
		private var _points:Vector.<Point>;
		private var _edges:Vector.<Edge>;
		
		public function Polygon( x:Number = 0, y:Number = 0, points:Vector.<Point> = null ) 
		{
			this.x = x;
			this.y = y;
			
			this.points = points;
			if ( this.points == null ) this.points = new Vector.<Point>();
			
			
		}
		
		public function get centroid():Point
		{
			var c:Point = new Point();
			for each( var p:Point in points )
			{
				c.x += p.x;
				c.y += p.y;
			}
			c.x /= points.length;
			c.y /= points.length;
			return c;
		}
		
		
		
		public function isSimple():Boolean
		{
			
			var edge:Edge, next:Edge;
			var p0:Point, p1:Point, p2:Point, p3:Point, ip:Point;
			var i:int, j:int;
			var maxId:int = edges[edges.length - 1 ].id;
			var tmpMaxId:int = maxId;
			
			search:for ( i = 0; i < edges.length; i++ )
			{
				
				edge = edges[ i ];
				
				if ( edge.id > maxId ) break search;
				
				for ( j = 0; j < edges.length; j++ )
				{
					next = edges[ j ];
					
					if ( edge == next ) continue;
					
					ip = edge.intersect( next );
					
					if ( ip != null )
					{
						return false;
						//p0 = edge.p0;
						//p1 = edge.p1;
						//
						//p2 = edge.p0;
						//p3 = edge.p1;
						//
						//points.push( ip );
					}
					
				}
			}
			return true;
		}
		
		public function draw( graphics:Graphics = null ):void
		{
			var ox:Number = x;
			var oy:Number = y;
			if ( graphics == null ) 
			{
				
				graphics = this.graphics;
				graphics.clear();
				graphics.lineStyle( strokeWidth, strokeColor, strokeAlpha );
				graphics.beginFill( fillColor, fillAlpha );
				ox = oy = 0;
			
			}
			
			var p:Point = points[ 0 ];
			graphics.moveTo( ox + p.x, oy + p.y );
			for each( p in points )
			{
				graphics.lineTo( ox + p.x, oy + p.y );
			}
			
		}
		
		
		/**
		 * determine si un point est à l'intérieur du polygone
		 * @param	p
		 * @return
		 */
		public function contains( p:Point ):Boolean
		{
			
			p.x -= x;
			p.y -= y;
			var i:int, counter:int = 0;
			var xinters:Number = 0;
			var p1:Point ,p2:Point ;
			var N:int = _points.length;
			
			p1 = _points[0];
			for (i = 1; i <= N; i++) 
			{
				p2 = _points[i % N];
				if ( p.y > ( ( p1.y < p2.y ) ? p1.y : p2.y ) ) //MIN( p1.y, p2.y )
				{
					if (p.y <= ( ( p1.y > p2.y ) ? p1.y : p2.y ) )//MAX(p1.y, p2.y) 
					{
						if (p.x <= ( ( p1.x > p2.x ) ? p1.x : p2.x ) ) //MAX(p1.x, p2.x)
						{
							if ( p1.y != p2.y ) 
							{
								xinters = (p.y - p1.y) * (p2.x - p1.x) / (p2.y - p1.y) + p1.x;
								if (p1.x == p2.x || p.x <= xinters)
								{
									counter++;
								}
							}
						}
					}
				}
				p1 = p2;
			}
			
			if (counter % 2 == 0)
			{
				return false;
			}
			return true;
			
			
		}
		
		
		
		public function get points():Vector.<Point> { return _points; }
		
		public function set points(value:Vector.<Point>):void 
		{
			_points = value;
		}
		
		public function get edges():Vector.<Edge> 
		{
			
			if ( _edges == null )
			{
				edges = new Vector.<Edge>();
				var i:int;
				var edge:Edge;
				for (i = 0; i < points.length; i++ )
				{
					edge = new Edge( points[ i ], points[ ( i + 1 ) % points.length ], i )
					_edges.push( edge );
				}
				
				for (i = 0; i < edges.length; i++ )
				{
					
					edges[ i ].prev = edges[ ( i - 1 < 0 ) ? edges.length - 1 : ( i-1 ) ];
					edges[ i ].next = edges[ ( i + 1 ) % edges.length ];
					
				}
			}
			return _edges; 
		}
		
		public function set edges(value:Vector.<Edge>):void 
		{
			_edges = value;
		}
		
	}

}